﻿/**	@file		type_list.hpp
 *	@date		(2009-12-18 00:29:12)/(2010-05-23 23:46:11)
 *-----------------------------------------------------------------------------
 *	@version	1.0.4.6
 *	@author		Nick Shallery	(nicknide@gmail.com)
 *	@copyright	YOU HAVE ALL LEFT WITH THIS CODE WHILE YOU KEEP COMMENT IN EVERY COPY.
 *-----------------------------------------------------------------------------
**/


#if			!defined(__LOLIX__TOY__TYPE_LIST__H__PP__K_IN_G__)
#define		__LOLIX__TOY__TYPE_LIST__H__PP__K_IN_G__

#if			!defined(__LOLIX__LOLIX_TYPE__K_IN_G__)
	#include	"../lolix_type.h"
#endif	//	!defined(__LOLIX__LOLIX_TYPE__K_IN_G__)

namespace lolix{namespace toy{
template<typename _Tval, typename _Tval1 = void, typename _Tval2 = void, typename _Tval3 = void, typename _Tval4 = void, typename _Tval5 = void>
class type_list;

namespace _help
{
	template<typename _Tlist, size_type _Tobj_level, size_type _Tcur_level>
	struct _get_values
	{
		typedef typename _get_values<typename _Tlist::pre_type, _Tobj_level, _Tcur_level-1>::type_result type_result;
	};

	template<typename _Tlist, size_type _T_level>
	struct _get_values<_Tlist, _T_level, _T_level>
	{
		typedef typename _Tlist::type type_result;
	};

	template<typename _Tlist>
	struct _get_types_inf
	{
		enum {size = 1};
		template<size_t _V_idx>
		struct types
		{
			typedef typename type::type_choise<_V_idx == 0, _Tlist, void>::type type;
		};
	};

	template<>
	struct _get_types_inf<void>
	{
		static const size_type size = 0;
		template<size_t _V_idx>
		struct types
		{
			typedef void type;
		};
	};

	template<typename _T0, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5>
	struct _get_types_inf< type_list<_T0, _T1, _T2, _T3, _T4, _T5> >
	{
		static const size_type size = type_list<_T0, _T1, _T2, _T3, _T4, _T5>::size;
		template<size_t _V_idx>
		struct types
		{
			typedef typename type_list<_T0, _T1, _T2, _T3, _T4, _T5>::template types<_V_idx>	_T_idx_type;
			typedef typename _T_idx_type::type type;
		};
	};
}


template<typename _Tval0, typename _Tval1, typename _Tval2, typename _Tval3, typename _Tval4, typename _Tval5>
class type_list
{
	typedef type_list<_Tval0, _Tval1, _Tval2, _Tval3, _Tval4, _Tval5>	this_type;
	struct	bad_type;
	enum {_size0 = _help::_get_types_inf<_Tval0>::size};
	enum {_size1 = _help::_get_types_inf<_Tval1>::size};
	enum {_size2 = _help::_get_types_inf<_Tval2>::size};
	enum {_size3 = _help::_get_types_inf<_Tval3>::size};
	enum {_size4 = _help::_get_types_inf<_Tval4>::size};
	enum {_size5 = _help::_get_types_inf<_Tval5>::size};
public:
	enum {size = _size0 + _size1 + _size2 + _size3 + _size4 + _size5};

	template<size_t _V_idx>
	struct types
	{
		const static bool _is_during_0 = _V_idx < _size0;
		const static bool _is_during_1 = _V_idx < _size0 + _size1;
		const static bool _is_during_2 = _V_idx < _size0 + _size1 + _size2;
		const static bool _is_during_3 = _V_idx < _size0 + _size1 + _size2 + _size3;
		const static bool _is_during_4 = _V_idx < _size0 + _size1 + _size2 + _size3 + _size4;
		const static bool _is_during_5 = _V_idx < _size0 + _size1 + _size2 + _size3 + _size4 + _size5;

		typedef typename _help::_get_types_inf<_Tval0>::template types<_V_idx>::type _T_during_0;
		typedef typename _help::_get_types_inf<_Tval1>::template types<_V_idx-_size0>::type _T_during_1;
		typedef typename _help::_get_types_inf<_Tval2>::template types<_V_idx-_size0-_size1>::type _T_during_2;
		typedef typename _help::_get_types_inf<_Tval3>::template types<_V_idx-_size0-_size1-_size2>::type _T_during_3;
		typedef typename _help::_get_types_inf<_Tval4>::template types<_V_idx-_size0-_size1-_size2-_size3>::type _T_during_4;
		typedef typename _help::_get_types_inf<_Tval5>::template types<_V_idx-_size0-_size1-_size2-_size3-_size4>::type _T_during_5;

		typedef
			typename   type::type_choise<_is_during_0, _T_during_0
			, typename type::type_choise<_is_during_1, _T_during_1
			, typename type::type_choise<_is_during_2, _T_during_2
			, typename type::type_choise<_is_during_3, _T_during_3
			, typename type::type_choise<_is_during_4, _T_during_4
			, typename type::type_choise<_is_during_5, _T_during_5
			, bad_type>
			::type >::type >::type >::type >::type>::type	type;
	};

	template<typename _Tadd>
	struct push_back
	{
		typedef type_list<this_type, _Tadd>	other;
	};
};


}}

#define	TYPE_LIST_BEGIN(type)	typedef ::lolix::toy::type_list<type>
#define	TYPE_LIST_PUSH_BACK(type)	::push_back<type>::other
#define	TYPE_LIST_END(type)		type
#endif	//	!defined(__LOLIX__TOY__TYPE_LIST__H__PP__K_IN_G__)
